#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pthread.h>
#include <pt_errors.h>
#include <windows.h>
#include <list>

#define WINSECONDS(x) x*1000
using namespace std;
class PoolEntrance
{
public:
	PoolEntrance(int Position,int Size)
	{
		this->Position=Position;
		this->Size=Size;
	}
	bool IsBefore(PoolEntrance* operand2)
	{
		return this->Position+this->Size<operand2->Position;
	}
	bool IsAfter(PoolEntrance* operand2)
	{
		return operand2->Position+operand2->Size<this->Position;
	}
	int GetEnd()
	{
		return this->Position+this->Size;
	}
	int Position;
	int Size;
	int RefCount;
};
class MemoryPool
{
public:
	MemoryPool(int MemorySize)
	{
		Memory=malloc(MemorySize);
		this->MemorySize=MemorySize;
		printf("memory pool created (size=%d)\n",MemorySize);
	}
	~MemoryPool()
	{
		free(Memory);
		printf("Memory pool freed\n");
	}
	void* Assign(int Size,PoolEntrance** NewEntrance)
	{
		printf("assign %d bytes requested\n",Size);
		*NewEntrance=new PoolEntrance(0,Size);
		It=Entrances.begin();
		//create first memory entrance
		if (Entrances.size()==0)
		{
			if (MemorySize>=Size)
			{
				Entrances.push_back(**NewEntrance);
				printf("first assign completed\n");
				return (void*)Memory;
			}
			else return 0;
		}
		else
		{
			//find memory to place new entrance

			It=Entrances.begin();
			int Pos=(It->Position==0)?It->Size+1:0;
			(*NewEntrance)->Position=Pos;
			printf("new entrance place search, Pos=%d\n",Pos);

			while (true)
			{
				if ((It!=Entrances.end())==0)
				{

					if ((*NewEntrance)->GetEnd()<MemorySize)
					{
						//add new entrance
						Entrances.insert(It,**NewEntrance);
						printf("entrance inserted, Pos=%d\n",(*NewEntrance)->Position);
						return (void*)((byte*)Memory+(*NewEntrance)->Position);
					}
					else
					{
						//throw memory overflow error
						printf("memory overflow\n");
						return 0;
					}
				}
				else//next element exists
				{

					if (It->Position>(*NewEntrance)->GetEnd())
					{
						//add new entrance
						Entrances.insert(It,**NewEntrance);
						printf("entrance inserted, Pos=%d\n",(*NewEntrance)->Position);
						return (void*)((byte*)Memory+(*NewEntrance)->Position);
					}
					else
					{
						//must iterate next

					}
				}
				It++;
			}
			return 0;
		}
	}
	void Free(PoolEntrance* OldEntrance)
	{
		printf("freeing memory requested\n");
		for (It=Entrances.begin(); It!=Entrances.end(); It++)
		{
			if (It->Position==OldEntrance->Position)
			{
				Entrances.erase(It);
				return;
			}
		}
		printf("freeing memory crashed\n");
	}
private:
	list<PoolEntrance> Entrances;
	list<PoolEntrance>::iterator It;
	void* Memory;
	int MemorySize;
};
MemoryPool* pool;
template <class ContainingType>
class Pointer
{
public:
	Pointer()
	{
		IsNull=true;
		printf("pointer created\n");
	}
	void Initialize()
	{
		printf("initializing pointed class\n");
		if (Data=(ContainingType*)pool->Assign(sizeof(ContainingType),&Entrance))
		{
			Entrance->RefCount=1;
			Data=new ContainingType();
			IsNull=false;
			printf("class created\n");
		}
		else
			printf("class creation crashed\n");

	}
	Pointer<ContainingType>(const Pointer<ContainingType>& p)
	{
		printf("copy ctor called, ref count=%i\n",this->Entrance->RefCount);
		this->Entrance=p.Entrance;
		this->Data=p.Data;
		this->IsNull=p.IsNull;
		this->Entrance->RefCount++;

	}
	Pointer<ContainingType> & operator=(const Pointer<ContainingType> &ref)
	{

		this->Entrance=ref.Entrance;

		this->Data=ref.Data;
		this->IsNull=ref.IsNull;
		this->Entrance->RefCount++;
		printf("= called, ref count =%d\n",ref.Entrance->RefCount);
		return *this;
	}

	~Pointer()
	{
		printf("pointer deleting, ref count=%d, enrance=%d\n",Entrance->RefCount,GetEntrance());
		Entrance->RefCount--;
		if (Entrance->RefCount==0)
		{
			pool->Free(Entrance);
			printf("class deleted\n");
		}

	}
	ContainingType* GetData()
		{
		return Data;
		}
	int GetEntrance() const
	{
		return Entrance->Position;
	}
private:
	PoolEntrance* Entrance;
	ContainingType* Data;
	bool IsNull;
};
class userclass
{
public:
	Pointer<userclass> reference;
	userclass()
	{
		a=0;
		b=0;
	}
	userclass(int a,int b)
	{
		this->a=a;
		this->b=b;
	}
	int GetA()
	{
		return a;
	}
	int GetB()
	{
		return b;
	}
private:
	int a,b;

};

typedef struct alarm_tag {
  int seconds;
  char message[64];
} alarm_t;

void* alarm_thread (void* arg) {
  alarm_t* alarm = (alarm_t*)arg;
  int status;
  status = pthread_detach(pthread_self());
  if (status != 0)
    printf("Detach thread");
  Sleep( WINSECONDS(alarm->seconds) );
  printf("(%d) %s\n", alarm->seconds, alarm->message);
  free(alarm);
  return NULL;
}

void* Test()
		{
			Pointer<userclass> p1;
			p1.Initialize();
			Pointer<userclass> p2;
			p2.Initialize();

		//	p1.GetData()->reference=p2;
		//	p2.GetData()->reference=p1;
			printf("end of Test() method\n");
		}
int main(int argc, char **argv) {
  int status;
  char line[128];
  char exitstr[]="exit";
  alarm_t* alarm;
  pthread_t thread;

  pool=new MemoryPool(100);
  Test();
  //Pointer<userclass>* p=new Pointer<userclass>();
  //Pointer<userclass>* p2=new Pointer<userclass>();
  //delete p;
  //delete p2;
  delete pool;


//  status = pthread_join(thread, NULL);
//  if ( status != 0 )
//    err_abort(status, "");
//  else
//    return status;

  while (true) {
    printf("Alarm> ");
    gets(line);
    if ( strlen(line) <= 1 ) continue;
    alarm = (alarm_t*)malloc( sizeof(alarm_t) );

    //exit command
    if (strcmp(line,exitstr)==0)
    {
    	printf("exit command\n");
    	break;
    }
    /* Parse input line into seconds (%d) and a message
     * (%64[^\n], consists of up to 64 characters
     * separated from the seconds by whitespace.
     */
    if ( sscanf(line, "%d %64[^\n]",&alarm->seconds, alarm->message) < 2 )
    {
      fprintf(stderr, "Bad command\n");
      free(alarm);
    }
    else
    {
      status = pthread_create(&thread, NULL, alarm_thread, alarm);
      if (status != 0);
        printf("Create alarm thread successful.\n");
    }
  }
  return 0;
}
